package serverapp

import (
	"context"
	"fmt"
	"strings"
	"time"
	"wanyu/server/engine/serverapp/codec"

	//grpc "github.com/micro/go-grpc"
	"wanyu/server/engine/wperror"

	wplog "wanyu/server/engine/wplog"

	"github.com/micro/go-micro"
	"github.com/micro/go-micro/client"
	"github.com/micro/go-micro/registry"
	"github.com/micro/go-micro/registry/mdns"
	"github.com/micro/go-micro/registry/memory"
	"github.com/micro/go-micro/server"
	grpc "github.com/micro/go-micro/service/grpc"
	"github.com/micro/go-plugins/registry/consul"
	"github.com/micro/go-plugins/registry/gossip"
	"net/http"
	_ "net/http/pprof"
	"os"
	"wanyu/server/protogo/public"
)

//BaseService microserver包装和实现
type BaseService interface {
	Init(opts ...Option) error
	Run() error
	String() string
	Client() client.Client
	Server() server.Server
}

//baseService 数据
type baseService struct {
	s    micro.Service
	opts Options
}

//NewBaseService 申请一个playerservice服务
func NewBaseService() BaseService {
	return &baseService{
		s: nil,
	}
}

func handlerWraper(fn server.HandlerFunc) server.HandlerFunc {
	return func(ctx context.Context, req server.Request, rsp interface{}) error {
		wplog.Debugf("recv rpc request from %s, method = %v, body = %v", req.Endpoint(), req.Method(), req.Body())
		err := fn(ctx, req, rsp)
		wplog.Debugf("rpc response, ec = %v, rsp = %v", err, rsp)

		return err
	}
}

func (bs *baseService) pprof() {
	if "" == bs.opts.srvCfg.DebugAddr {
		wplog.Error("debug addr is empty, process exit...")
		os.Exit(1)
	}

	go func() {
		if err := http.ListenAndServe(bs.opts.srvCfg.DebugAddr, nil); nil != err {
			wplog.Errorf("start debug listen is failed, ec = %v, process exit...", err)
			os.Exit(1)
		}
	}()
}

//Init 初始化
func (bs *baseService) Init(opts ...Option) error {

	for _, o := range opts {
		o(&bs.opts)
	}

	//pprof
	if !bs.opts.disableDebugAddr {
		bs.pprof()
	}

	//创建微服务
	switch bs.opts.serviceType {
	case MicroType:
		bs.s = micro.NewService(
			micro.Server(server.NewServer(server.Codec("application/json", codec.NewCodec))),
			micro.Client(client.NewClient(client.Codec("application/json", codec.NewCodec))),
			micro.Context(bs.opts.context),
			micro.Name(bs.opts.srvCfg.SrvName),
			micro.Version(bs.opts.srvCfg.Version),
			micro.RegisterTTL(time.Second*time.Duration(bs.opts.srvCfg.TTL)),
			micro.RegisterInterval(time.Second*time.Duration(bs.opts.srvCfg.Interval)),
			micro.Address(bs.opts.srvCfg.Addr),
			micro.Registry(bs.newRegistry(bs.opts.srvCfg.Registry)),
			micro.HandleSignal(!bs.opts.signal),
			//micro.WrapHandler(handlerWraper),
		)
		public.RegisterCmdHandler(bs.s.Server(), &baseCmd{callback: bs.opts.cmdFn, debugAddr: bs.opts.srvCfg.DebugAddr})
		//设置错误模块的编号
		wperror.SetServerID(bs.opts.srvCfg.SrvName)
	case GrpcType:
		bs.s = grpc.NewService(
			micro.Context(bs.opts.context),
			micro.Name(bs.opts.srvCfg.SrvName),
			micro.Version(bs.opts.srvCfg.Version),
			micro.RegisterTTL(time.Second*time.Duration(bs.opts.srvCfg.TTL)),
			micro.RegisterInterval(time.Second*time.Duration(bs.opts.srvCfg.Interval)),
			micro.Address(bs.opts.srvCfg.Addr),
			micro.Registry(bs.newRegistry(bs.opts.srvCfg.Registry)),
			micro.HandleSignal(!bs.opts.signal),
		)

	default:
		return fmt.Errorf("invalid service type")
	}

	//退出之前等待所有handler完成处理

	bs.s.Server().Init(
		server.Wait(nil),
	)
	return nil
}

func (bs *baseService) newRegistry(rn string) registry.Registry {
	//解析consul注册地址
	if strings.HasPrefix(rn, "consul") {
		consulAddr := strings.Split(bs.opts.srvCfg.Registry, "=")
		if len(consulAddr) < 2 || "" == consulAddr[1] {
			return nil
		}

		return consul.NewRegistry(registry.Addrs(consulAddr[1]))
	}

	switch rn {
	case "gossip":
		return gossip.NewRegistry()
	case "memory":
		return memory.NewRegistry()
		//"mdns"
	default:
		return mdns.NewRegistry()
	}
}

func (bs *baseService) Client() client.Client {
	return bs.s.Client()
}

func (bs *baseService) Server() server.Server {
	return bs.s.Server()
}

//Run 运行
func (bs *baseService) Run() error {
	if err := bs.s.Run(); err != nil {
		return err
	}
	return nil
}

func (bs *baseService) String() string {
	return fmt.Sprintf("windService{service:%v,cfg:%+v}",
		bs.s.String(), bs.opts.srvCfg)
}
